﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System.Collections;
using System.Collections.Generic;
using System;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Globalization;
using DevExpress.AgDataGrid.Data.Helpers;
using System.ComponentModel;
namespace DevExpress.AgDataGrid.Data {
	public class DataHelperBase {
		DataController controller;
		DataColumnCollection columns;
		public DataHelperBase(DataController controller) {
			this.controller = controller;
		}
		protected virtual DataController Controller { get { return controller; } }
		public virtual DataColumnCollection Columns {
			get {
				if(columns == null) {
					columns = new DataColumnCollection();
					PopulateColumns();
				}
				return columns;
			}
		}
		public virtual int RowCount { get { return 0; } }
		public virtual object GetRow(int listIndex) { return null; }
		public virtual bool IsValidListIndex(int listIndex) { return false; }
		protected virtual void PopulateColumns() {
			Columns.Clear();
		}
		public virtual object GetRowValue(int listIndex, DataColumn column) { return null; }
		public virtual void SetRowValue(int listIndex, DataColumn column, object value) { }
		public virtual void DeleteRow(int listIndex) { }
	}
	public class DataHelperList : DataHelperBase {
		IList dataSource;
		public DataHelperList(DataController controller) : base(controller) { }
		public DataHelperList(DataController controller, IList dataSource)
			: base(controller) {
			this.dataSource = dataSource;
		}
		public virtual IList DataSource { get { return dataSource; } }
		public override int RowCount { get { return DataSource.Count; } }
		public override object GetRow(int listIndex) {
			if(!IsValidListIndex(listIndex)) return null;
			return DataSource[listIndex];
		}
		public override bool IsValidListIndex(int listIndex) {
			return listIndex >= 0 && listIndex < RowCount;
		}
		protected override void PopulateColumns() {
			base.PopulateColumns();
			Type type = GetIndexerPropertyType();
			if(type == null) {
				if(RowCount == 0) return;
				type = DataSource[0].GetType();
			}
			if(type.IsPrimitive || type == typeof(string) || type == typeof(DateTime) || type == typeof(decimal)) {
				Columns.Add(new DataColumnPrimitive(type));
				return;
			}
			PropertyInfo[] props = type.GetProperties();
			foreach(PropertyInfo prop in props) {
				Columns.Add(new DataColumnBound(prop));
			}
		}
		public Type GetIndexerPropertyType() {
			Type type = DataSource.GetType();
			if(DataSource.Count == 0 && type.IsArray) {
				return type.GetElementType();
			}
			PropertyInfo[] props = type.GetProperties();
			for(int i = 0; i < props.Length; i++) {
				if("Item".Equals(props[i].Name) && props[i].PropertyType != typeof(object)) {
					return props[i].PropertyType;
				}
			}
			return null;
		}
		public override object GetRowValue(int listIndex, DataColumn column) {
			if(column == null || !IsValidListIndex(listIndex)) return null;
			return column.GetValue(listIndex, GetRow(listIndex));
		}
		public override void SetRowValue(int listIndex, DataColumn column, object value) {
			if(column == null || column.ReadOnly || !IsValidListIndex(listIndex)) return;
			column.SetValue(listIndex, GetRow(listIndex), value);
		}
		public override void DeleteRow(int listIndex) {
			if(!Controller.OnRowDeleting(listIndex)) return;
			try {
				DataSource.RemoveAt(listIndex);
			} finally {
				Controller.OnRowDeleted(listIndex);
			}
		}
	}
	public class DataColumn {
		string name;
		bool readOnly;
		Type type;
		protected DataColumn(string name, Type type, bool readOnly) {
			this.name = name;
			this.type = type;
			this.readOnly = readOnly;
		}
		public string Name { get { return name; } }
		public bool ReadOnly { get { return readOnly; } }
		public Type Type { get { return type; } }
		public virtual object GetValue(int listIndex, object row) { return null; }
		public override string ToString() {
			return Name;
		}
		public virtual void SetValue(int listIndex, object row, object value) { }
		public object ConvertValue(object value) { return ConvertValue(value, false); }
		public virtual object ConvertValue(object value, bool throwException) {
			try {
				if(value != null && !Type.IsAssignableFrom(value.GetType()))
					value = Convert.ChangeType(value, Type, CultureInfo.CurrentCulture);
			}
			catch {
				if(throwException) throw;
			}
			return value;
		}
	}
	public class DataColumnBound : DataColumn {
		PropertyInfo propInfo;
		public DataColumnBound(PropertyInfo prop)
			: base(prop.Name, prop.PropertyType, !prop.CanWrite) {
			this.propInfo = prop;
		}
		public PropertyInfo PropertyInfo { get { return propInfo; } }
		public override object GetValue(int listIndex, object row) {
			return PropertyInfo.GetValue(row, null);
		}
		public override void SetValue(int listIndex, object row, object value) {
			value = ConvertValue(value);
			PropertyInfo.SetValue(row, value, null);
		}
	}
	public class DataColumnPrimitive : DataColumn {
		public DataColumnPrimitive(Type type)
			: base("Column", type, false) {
		}
		public override object GetValue(int listIndex, object row) {
			return row;
		}
	}
	public class DataColumnCollection : List<DataColumn> {
		public DataColumn this[string name] {
			get {
				foreach(DataColumn column in this) {
					if(column.Name == name)
						return column;
				}
				return null;
			}
		}
		public override string ToString() {
			return "DataColumnCollection, Count: " + Count.ToString();
		}
	}
	public class ListSourceRowIndexCollection : Collection<int> {
		bool empty = true;
		public bool IsEmpty {
			get { return empty; }
			set {
				if(empty == value) return;
				empty = value;
				Clear();
			}
		}
		protected internal new List<int> Items { get { return (List<int>)base.Items; } }
		public int GetListSourceIndex(int controllerIndex) {
			if(IsEmpty && controllerIndex >= 0) return controllerIndex;
			if(!IsValidControllerIndex(controllerIndex)) return DataController.InvalidRow;
			return this[controllerIndex];
		}
		public int GetControllerIndex(int listSourceIndex) {
			if(IsEmpty && listSourceIndex >= 0) return listSourceIndex;
			int res = IndexOf(listSourceIndex);
			return res == -1 ? DataController.InvalidRow : res;
		}
		public void CreateList(int count) {
			IsEmpty = false;
			Items.Capacity = count;
			for(int i = 0; i < count; i++) Add(i);
		}
		public void Sort(Comparison<int> comparison) {
			Items.Sort(comparison);
		}
		protected bool IsValidControllerIndex(int controllerIndex) {
			return controllerIndex >= 0 && controllerIndex < Count;
		}
	}	
	public class ValueComparer : IComparer {
		CompareInfo compareInfo = CultureInfo.CurrentCulture.CompareInfo;
		public int Compare(object x, object y) {
			if(x == DBNull.Value) x = null;
			if(y == DBNull.Value) y = null;
			if(x == y) return 0;
			if(x == null) return -1;
			if(y == null) return 1;
			return CompareCore(x, y);
		}
		int CompareCore(object a, object b) {
			if(a == b) return 0;
			if(a == null) return -1;
			if(b == null) return 1;
			string str = a as string;
			string str2 = b as string;
			if((str != null) && (str2 != null)) {
				return compareInfo.Compare(str, str2);
			}
			IComparable comparable = a as IComparable;
			if(comparable == null) 
				throw new ArgumentException("IComparable is not implemented");
			return comparable.CompareTo(b);
		}
		public bool ObjectEquals(object x, object y) {
			if(x == DBNull.Value) x = null;
			if(y == DBNull.Value) y = null;
			return Object.Equals(x, y);
		}
	}
}
